﻿@using Radzen
@using Radzen.Blazor
@implements IDisposable
@typeparam TItem
@code {
    public override async Task SetParametersAsync(ParameterView parameters)
    {
        if (parameters.DidParameterChange(nameof(Visible), Visible))
        {
            if (Grid != null)
            {
                await Grid.ChangeState();
            }
        }

        await base.SetParametersAsync(parameters);
    }

    string _title;
    [Parameter]
    public string Title
    {
        get
        {
            return _title;
        }
        set
        {
            if (_title != value)
            {
                _title = value;

                if (Grid != null)
                {
                    Grid.ChangeState().Wait();
                }
            }
        }
    }

    [Parameter]
    public string Property { get; set; }

    [Parameter]
    public string SortProperty { get; set; }

    [Parameter]
    public string FilterProperty { get; set; }

    [Parameter]
    public object FilterValue { get; set; }

    [Parameter]
    public object SecondFilterValue { get; set; }

    string _filterOperator;

    [Parameter]
    public string FilterOperator
    {
        get
        {
            if (string.IsNullOrEmpty(_filterOperator))
            {
                _filterOperator = Type == "string" && string.IsNullOrEmpty(Format) ? "contains" : "eq";
            }

            return _filterOperator;
        }
        set
        {
            if (_filterOperator != value)
            {
                _filterOperator = value;
            }
        }
    }

    string _secondFilterOperator;
    [Parameter]
    public string SecondFilterOperator
    {
        get
        {
            if (string.IsNullOrEmpty(_secondFilterOperator))
            {
                _secondFilterOperator = Type == "string" && string.IsNullOrEmpty(Format) ? "contains" : "eq";
            }

            return _secondFilterOperator;
        }
        set
        {
            if (_secondFilterOperator != value)
            {
                _secondFilterOperator = value;
            }
        }
    }

    [Parameter]
    public LogicalFilterOperator LogicalFilterOperator { get; set; } = LogicalFilterOperator.And;

    Dictionary<string, string> _filterOperators;
    public Dictionary<string, string> FilterOperators
    {
        get
        {
            if (_filterOperators == null)
            {
                _filterOperators = new Dictionary<string, string>();

                if (Type == "string" && string.IsNullOrEmpty(Format))
                {
                    _filterOperators.Add("startswith", this.Grid != null ? this.Grid.StartsWithText : "Starts with");
                    _filterOperators.Add("contains", this.Grid != null ? this.Grid.ContainsText : "Contains");
                    _filterOperators.Add("endswith", this.Grid != null ? this.Grid.EndsWithText : "Ends with");
                }

                _filterOperators.Add("eq", this.Grid != null ? this.Grid.EqualsText : "Equals");
                _filterOperators.Add("ne", this.Grid != null ? this.Grid.NotEqualsText : "Not equals");

                if (Type != "string" || (Type == "string" && !string.IsNullOrEmpty(Format)))
                {
                    _filterOperators.Add("lt", this.Grid != null ? this.Grid.LessThanText : "Less than");
                    _filterOperators.Add("le", this.Grid != null ? this.Grid.LessThanOrEqualsText : "Less than or equals");
                    _filterOperators.Add("gt", this.Grid != null ? this.Grid.GreaterThanText : "Greater than");
                    _filterOperators.Add("ge", this.Grid != null ? this.Grid.GreaterThanOrEqualsText : "Greater than or equals");
                }
            }

            return _filterOperators;
        }
    }

    [Parameter]
    public string Width { get; set; }

    [Parameter]
    public string Type { get; set; } = "string";

    [Parameter]
    public string Format { get; set; }

    [Parameter]
    public string FormatString { get; set; }

    [Parameter]
    public string CssClass { get; set; }

    [Parameter]
    public string HeaderCssClass { get; set; }

    [Parameter]
    public string FooterCssClass { get; set; }

    [Parameter]
    public bool Filterable { get; set; } = true;

    [Parameter]
    public bool Sortable { get; set; } = true;

    [Parameter]
    public bool Bubble { get; set; } = true;

    [Parameter]
    public bool Visible { get; set; } = true;

    [Parameter]
    public TextAlign TextAlign { get; set; } = TextAlign.Left;

    [Parameter]
    public RenderFragment<TItem> Template { get; set; }

    [Parameter]
    public RenderFragment<TItem> EditTemplate { get; set; }

    [Parameter]
    public RenderFragment HeaderTemplate { get; set; }

    [Parameter]
    public RenderFragment FooterTemplate { get; set; }

    [Parameter]
    public RenderFragment<RadzenGridColumn<TItem>> FilterTemplate { get; set; }

    RadzenGrid<TItem> _grid;

    [CascadingParameter]
    public RadzenGrid<TItem> Grid
    {
        get
        {
            return _grid;
        }
        set
        {
            if (_grid != value)
            {
                _grid = value;
                _grid.AddColumn(this);

                var property = GetFilterProperty();

                if (!string.IsNullOrEmpty(property))
                {
                    _filterPropertyType = PropertyAccess.GetPropertyType(typeof(TItem), property);
                    if (_filterPropertyType != null)
                    {
                        if (PropertyAccess.IsNumeric(_filterPropertyType))
                        {
                            Type = "number";
                        }
                        else if (_filterPropertyType == typeof(bool) || _filterPropertyType == typeof(bool?))
                        {
                            Type = "boolean";
                        }
                        else if (_filterPropertyType == typeof(DateTime) || _filterPropertyType == typeof(DateTime?))
                        {
                            Type = "string";
                            Format = "date-time";
                        }
                        else if (_filterPropertyType == typeof(DateTimeOffset) || _filterPropertyType == typeof(DateTimeOffset?))
                        {
                            Type = "string";
                            Format = "date-time-offset";
                        }
                        else if (_filterPropertyType == typeof(Guid) || _filterPropertyType == typeof(Guid?))
                        {
                            Type = "string";
                            Format = "uuid";
                        }
                    }
                }
            }
        }
    }

    Type _filterPropertyType;

    internal Type FilterPropertyType
    {
        get
        {
            return _filterPropertyType;
        }
    }

    public string GetStyle(bool forCell = false)
    {
        var style = new List<string>();

        var width = GetWidth();

        if (width != null)
        {
            style.Add($"width:{width}");
        }
        else if (Grid != null && Grid.ColumnWidth != null)
        {
            style.Add($"width:{Grid.ColumnWidth}");
        }

        if (forCell && TextAlign != TextAlign.Left)
        {
            style.Add($"text-align:{Enum.GetName(typeof(TextAlign), TextAlign).ToLower()};");
        }

        return string.Join(";", style);
    }

    public string GetSortProperty()
    {
        if (!string.IsNullOrEmpty(SortProperty))
        {
            return SortProperty;
        }
        else
        {
            return Property;
        }
    }

    internal SortOrder? SortOrder { get; set; }

    public string GetFilterProperty()
    {
        if (!string.IsNullOrEmpty(FilterProperty))
        {
            return FilterProperty;
        }
        else
        {
            return Property;
        }
    }

    internal void SetFilterValue(object value, bool isFirst = true)
    {
        if (Format == "date-time-offset" && value != null && value is DateTime?)
        {
            DateTimeOffset? offset = DateTime.SpecifyKind((DateTime)value, DateTimeKind.Utc);
            value = offset;
        }

        if (isFirst)
        {
            FilterValue = value;
        }
        else
        {
            SecondFilterValue = value;
        }
    }

    internal void SetFilterOperator(string value)
    {
        FilterOperator = value;
    }

    internal void SetSecondFilterOperator(string value)
    {
        SecondFilterOperator = value;
    }

    internal void SetLogicalFilterOperator(LogicalFilterOperator value)
    {
        LogicalFilterOperator = value;
    }

    string runtimeWidth;
    internal void SetWidth(string value)
    {
        runtimeWidth = value;
    }

    internal string GetWidth()
    {
        return !string.IsNullOrEmpty(runtimeWidth) ? runtimeWidth : Width;
    }

    public void Dispose()
    {
        Grid?.RemoveColumn(this);
    }
}
